package cn.hjnu.heartRpc.framework.core.registy.nacos;


import cn.hjnu.heartRpc.framework.core.common.event.IRpcEvent;
import cn.hjnu.heartRpc.framework.core.common.event.IRpcListenerLoader;
import cn.hjnu.heartRpc.framework.core.common.event.IRpcUpdateEvent;
import cn.hjnu.heartRpc.framework.core.common.event.data.URLChangeWrapper;
import cn.hjnu.heartRpc.framework.core.registy.RegistryService;
import cn.hjnu.heartRpc.framework.core.registy.URL;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Cluster;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.healthcheck.AbstractHealthChecker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.stream.Collectors;

import static cn.hjnu.heartRpc.framework.core.common.cache.CommonClientCache.CONNECT_MAP;

/***
* @description TODO
* @param null
* @return
* @author OTTO
* @date 2023/7/20 22:18
*/
@Slf4j
public class NacosRegister extends AbstractRegister implements RegistryService {

    private NamingService naming;

    public NacosRegister(String address) {
        try {
            this.naming = NamingFactory.createNamingService(address);
        } catch (NacosException e) {
            log.error("连接到Nacos时有错误发生: ", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public void register(URL url) {
        try {
            naming.registerInstance(url.getServiceName(), url.getParameters().get("host"), Integer.valueOf(url.getParameters().get("port")));
            Cluster cluster = new Cluster();
            cluster.setHealthChecker(new AbstractHealthChecker.None());
        } catch (NacosException e) {
            log.error("注册失败");
            throw new RuntimeException(e);
        }
        super.register(url);
    }

    @Override
    public void unRegister(URL url) {
        super.unRegister(url);
    }

    @Override
    public void subscribe(URL url) {
        try {
            naming.subscribe(url.getServiceName(),event -> {
                if (event instanceof NamingEvent) {
                    System.out.println(((NamingEvent) event).getServiceName());
                    System.out.println(((NamingEvent) event).getInstances());
//                    System.out.println(CONNECT_MAP);
                    URLChangeWrapper urlChangeWrapper = new URLChangeWrapper();
                    List<Instance> instances = ((NamingEvent) event).getInstances();
                    List<String> address = instances.stream().map(instance ->
                            StringUtils.join(instance.getIp(), ":", instance.getPort())
                    ).collect(Collectors.toList());
                    urlChangeWrapper.setProviderUrl(address);
                    urlChangeWrapper.setServiceName(((NamingEvent) event).getServiceName());
                    IRpcEvent iRpcEvent = new IRpcUpdateEvent(urlChangeWrapper);
                    IRpcListenerLoader.sendEvent(iRpcEvent);
                }
            });
        } catch (NacosException e) {
            log.error("订阅失败");
            throw new RuntimeException(e);
        }
        super.subscribe(url);
    }

    @Override
    public void doUnSubscribe(URL url) {
        super.doUnSubscribe(url);
    }

    /**
     * 留给子类扩展
     *
     * @param url
     */
    @Override
    public void doAfterSubscribe(URL url) {

    }

    /**
     * 留给子类扩展
     *
     * @param url
     */
    @Override
    public void doBeforeSubscribe(URL url) {

    }

    /**
     * 留给子类扩展
     *
     * @param serviceName
     * @return
     */
    @Override
    public List<String> getProviderIps(String serviceName) {
        List<String> ips;
        try {
            List<Instance> allInstances = naming.getAllInstances(serviceName);
            ips = allInstances.stream().map((instance)->{
                String ip = instance.getIp();
                int port = instance.getPort();
                String address = StringUtils.join(ip,":", port);
                return address;
            }).collect(Collectors.toList());
        } catch (NacosException e) {
            log.error("获取实例失败");
            throw new RuntimeException(e);
        }
        return ips;
    }
}
